﻿Public Class clsMPM
#Region "TaskAnalyzer"
    Private ProjectCalculated As Boolean
    Private ProjectLength As Int32
    Public Function AnaylseTasks(ByRef working As Dictionary(Of Int32, clsTask), ByRef ht As Dictionary(Of Int32, clsTask), ByVal parent As Int32, ByRef projectInfo As clsProject)
        Try
            Do While working.Count > 0
                Dim temp As Dictionary(Of Int32, clsTask) = GetTaskByParent(ht, parent, working)
                If temp.Count = 0 Then
                    Return False
                End If
                For Each tempitm As clsTask In temp.Values
                    Dim actTask As clsTask = ht(tempitm.Key)
                    actTask.FAZ = If(parent = 0, 0, GetMaxValue(working, ht, actTask, projectInfo))
                    actTask.FEZ = actTask.FAZ + actTask.Duration
                    If working.ContainsKey(actTask.Key) Then
                        working.Remove(actTask.Key)
                    End If
                Next
                For Each tempitm As clsTask In temp.Values
                    Dim actTask As clsTask = ht(tempitm.Key)
                    If AnaylseTasks(working, ht, actTask.Key, projectInfo) Then
                        If ProjectCalculated = False Then
                            'backwards
                            Rueck(actTask, ht, projectInfo)
                            ProjectCalculated = True
                        End If
                    End If
                Next
            Loop
            Return True
        Catch ex As Exception
            Throw
        End Try
    End Function
    Private Function Rueck(ByVal acttask As clsTask, ByRef ht As Dictionary(Of Int32, clsTask), ByRef projInfo As clsProject) As Boolean
        Try
            For Each pretask As Int32 In acttask.Pre
                If acttask.Pre.Count = 1 And acttask.Pre(0) = 0 Then
                    Return True
                Else
                    Dim sez As Int32 = ProjectLength
                    If acttask.Post.Count > 0 AndAlso acttask.Post(0) <> 0 Then
                        For Each post As Int32 In acttask.Post
                            Dim postTask As clsTask = ht(post)
                            sez = Math.Min(sez, postTask.SAZ)
                        Next
                    Else
                        sez = acttask.FEZ
                        ProjectLength = sez
                    End If
                    acttask.SEZ = sez
                    acttask.SAZ = sez - acttask.Duration
                    acttask.Puffer = sez - acttask.FEZ
                    If acttask.Puffer = 0 Then
                        If Not projInfo.CriticalPath.Contains(acttask.Key) Then
                            projInfo.CriticalPath.Add(acttask.Key)
                        End If
                    End If
                End If
                Rueck(ht(pretask), ht, projInfo)
            Next
            Return True
        Catch ex As Exception
            Throw
        End Try
    End Function

    Private Function GetMaxValue(ByRef working As Dictionary(Of Int32, clsTask), ByRef ht As Dictionary(Of Int32, clsTask), ByVal task As clsTask, ByRef projInfo As clsProject)
        Try
            Dim ret As Int32 = 0
            For Each pre As Int32 In task.Pre
                Dim preTask As clsTask = ht(pre)
                If preTask.FEZ = 0 Then
                    'pre not calced, duration=0 => super source
                    If preTask.Duration > 0 Then
                        For Each parent As String In preTask.Pre
                            AnaylseTasks(working, ht, parent, projInfo)
                        Next
                    End If
                End If
                ret = Math.Max(ret, preTask.FEZ)
            Next
            Return ret
        Catch ex As Exception
            Throw
        End Try
    End Function
    Private Function GetTaskByParent(ByVal list As Dictionary(Of Int32, clsTask), ByVal parent As Int32, ByVal working As Dictionary(Of Int32, clsTask)) As Dictionary(Of Int32, clsTask)
        Try
            Dim ret As New Dictionary(Of Int32, clsTask)
            For Each itm As clsTask In list.Values
                For Each listitm As Int32 In itm.Pre
                    If listitm = parent Then
                        Dim bAllowed As Boolean = True
                        For Each pre As Int32 In itm.Pre
                            If pre <> 0 Then
                                Dim preTask As clsTask = list(CLng(pre))
                                If preTask.FEZ = 0 Then
                                    If preTask.Duration > 0 Then
                                        bAllowed = False
                                        Exit For
                                    End If
                                End If
                            End If
                        Next
                        If bAllowed Then
                            If working.ContainsKey(itm.Key) Then
                                ret.Add(itm.Key, itm)
                            End If
                        End If
                        Exit For
                    End If
                Next
            Next
            Return ret
        Catch ex As Exception
            Throw
        End Try
    End Function
#End Region
End Class
